<template>
  <div class="overview-map" :class="{ 'visible': isVisible }">
    <div class="overview-header">
      <span class="overview-title">概览图</span>
      <div class="overview-controls">
        <button 
          class="control-btn" 
          @click="toggleVisibility"
          :title="isVisible ? '隐藏概览图' : '显示概览图'"
        >
          {{ isVisible ? '−' : '+' }}
        </button>
      </div>
    </div>
    
    <div class="overview-content" v-show="isVisible">
      <div class="overview-container" ref="overviewContainer" @click="handleOverviewClick" :style="overviewContainerStyle">
        <!-- 缩略图容器 -->
        <div class="thumbnail-container" ref="thumbnailContainer">
          <!-- 缩略图内容 -->
          <div 
            class="thumbnail-content" 
            :style="thumbnailStyle"
            ref="thumbnailContent"
          >
            <!-- 这里会包含主容器的克隆内容 -->
          </div>
        </div>
        
        <!-- 视口指示器 -->
        <div 
          class="viewport-indicator" 
          :style="viewportIndicatorStyle"
          ref="viewportIndicator"
          @mousedown="startDragViewport"
          :class="{ 'dragging': isDraggingViewport }"
        ></div>
        
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'OverviewMap',
  props: {
    // 主容器的引用
    mainContainer: {
      required: true
    },
    // 是否显示概览图
    visible: {
      type: Boolean,
      default: true
    },
    // 页面缩放比例
    zoomLevel: {
      type: Number,
      default: 1
    }
  },
  data() {
    return {
      isVisible: this.visible,
      containerRect: null,
      overviewRect: null,
      scale: 0.1, // 缩略图缩放比例
      scrollPosition: { x: 0, y: 0 },
      containerSize: { width: 0, height: 0 },
      isInitialized: false,
      clonedContent: null,
      // 视口拖动相关状态
      isDraggingViewport: false,
      dragStartPosition: { x: 0, y: 0 },
      dragStartScrollPosition: { x: 0, y: 0 }
    }
  },
  computed: {
    thumbnailStyle() {
      if (!this.mainContainer) return {}
      
      return {
        transform: `scale(${this.scale})`,
        transformOrigin: 'top left',
        width: `${this.mainContainer.scrollWidth}px`,
        height: `${this.mainContainer.scrollHeight}px`,
        position: 'absolute',
        top: 0,
        left: 0
      }
    },
    
    // 概览图容器样式
    overviewContainerStyle() {
      if (!this.mainContainer) return {}
      
      // 计算缩放后的尺寸
      const scaledWidth = this.mainContainer.scrollWidth * this.scale
      const scaledHeight = this.mainContainer.scrollHeight * this.scale
      
      // 确保概览图容器能容纳所有缩放后的内容
      // 使用实际缩放后的尺寸，而不是强制最小值
      return {
        width: `${Math.max(200, scaledWidth)}px`,
        height: `${Math.max(150, scaledHeight)}px`,
        minWidth: '200px',
        minHeight: '150px'
      }
    },
    
    viewportIndicatorStyle() {
      if (!this.containerRect || !this.overviewRect || !this.mainContainer) return {}
      
      // 获取滚动容器（zoom-container）
      const scrollContainer = this.mainContainer.parentElement
      if (!scrollContainer) return {}
      
      // 获取当前视口尺寸（从滚动容器获取）
      const viewportWidth = scrollContainer.clientWidth
      const viewportHeight = scrollContainer.clientHeight
      
      // 计算视口指示器在概览图中的位置和大小
      // 需要考虑页面缩放对内容尺寸的影响
      // 正确的比例计算：使用实际的缩放比例，而不是概览图容器的尺寸
      const scaleX = this.scale
      const scaleY = this.scale
      
      // 计算视口指示器的位置（基于滚动位置）
      const left = this.scrollPosition.x * scaleX
      const top = this.scrollPosition.y * scaleY
      
      // 计算视口指示器的大小
      // 当页面缩放时，视口在内容中的相对大小会变化
      // 正确的逻辑：视口在内容中的实际大小 = 视口物理大小 / 缩放比例
      // 当页面放大时（zoomLevel > 1），视口在内容中覆盖的区域变小
      // 当页面缩小时（zoomLevel < 1），视口在内容中覆盖的区域变大
      const scaledViewportWidth = viewportWidth / this.zoomLevel
      const scaledViewportHeight = viewportHeight / this.zoomLevel
      
      // 计算视口指示器在概览图中的大小
      // 使用缩放后的视口尺寸来计算
      const width = scaledViewportWidth * scaleX
      const height = scaledViewportHeight * scaleY
      
      
      // 确保指示器不会超出概览图边界
      const maxLeft = this.overviewRect.width - width
      const maxTop = this.overviewRect.height - height
      
      const finalLeft = Math.max(0, Math.min(left, maxLeft))
      const finalTop = Math.max(0, Math.min(top, maxTop))
      
      return {
        left: `${finalLeft}px`,
        top: `${finalTop}px`,
        width: `${width}px`,
        height: `${height}px`
      }
    }
  },
  mounted() {
    // 等待DOM更新后再初始化
    this.$nextTick(() => {
      if (!this.isInitialized) {
        this.initializeOverview()
        this.setupEventListeners()
      }
    })
  },
  
  beforeDestroy() {
    this.removeEventListeners()
    // 清理拖动事件监听器
    if (this.isDraggingViewport) {
      document.removeEventListener('mousemove', this.handleDragViewportMove)
      document.removeEventListener('mouseup', this.handleDragViewportEnd)
    }
  },
  
  methods: {
    // 初始化概览图
    async initializeOverview() {
      if (!this.mainContainer) {
        // 延迟重试
        setTimeout(() => {
          this.initializeOverview()
        }, 1000)
        return
      }
      
      try {
        // 等待DOM更新
        await this.$nextTick()
        
        // 获取容器尺寸
        this.updateContainerSize()
        
        // 创建缩略图内容
        this.createThumbnailContent()
        
        // 更新视口指示器位置
        this.updateViewportIndicator()
        
      } catch (error) {
        console.error('初始化概览图失败:', error)
      }
    },
    
    // 设置事件监听器
    setupEventListeners() {
      if (!this.mainContainer) return
      
      // 获取滚动容器（zoom-container）
      const scrollContainer = this.mainContainer.parentElement
      if (scrollContainer) {
        // 监听滚动事件
        scrollContainer.addEventListener('scroll', this.handleScroll, { passive: true })
      }
      
      // 监听窗口大小变化
      window.addEventListener('resize', this.handleResize)
      
      // 监听内容变化事件（自定义事件）
      this.$root.$on('content-changed', this.handleContentChanged)
    },
    
    // 移除事件监听器
    removeEventListeners() {
      if (!this.mainContainer) return
      
      // 获取滚动容器（zoom-container）
      const scrollContainer = this.mainContainer.parentElement
      if (scrollContainer) {
        scrollContainer.removeEventListener('scroll', this.handleScroll)
      }
      
      window.removeEventListener('resize', this.handleResize)
      this.$root.$off('content-changed', this.handleContentChanged)
    },
    
    // 更新容器尺寸
    updateContainerSize() {
      if (!this.mainContainer) return
      
      const rect = this.mainContainer.getBoundingClientRect()
      this.containerSize = {
        width: rect.width,
        height: rect.height
      }
    },
    
    // 创建缩略图内容
    createThumbnailContent() {
      if (!this.mainContainer || !this.$refs.thumbnailContent) return
      
      try {
        // 克隆zoom-wrapper的内容
        const clonedNode = this.mainContainer.cloneNode(true)
        
        // 设置克隆节点的样式，确保显示完整内容
        clonedNode.style.position = 'static'
        clonedNode.style.overflow = 'visible'
        clonedNode.style.width = '100%'
        clonedNode.style.height = '100%'
        clonedNode.style.transform = 'none' // 移除原有的transform
        clonedNode.style.transformOrigin = 'initial'
        
        // 清空缩略图容器并添加克隆内容
        this.$refs.thumbnailContent.innerHTML = ''
        this.$refs.thumbnailContent.appendChild(clonedNode)
        
        // 计算合适的缩放比例
        this.calculateOptimalScale()
        
      } catch (error) {
        console.error('创建缩略图内容失败:', error)
      }
    },
    
    // 计算合适的缩放比例
    calculateOptimalScale() {
      if (!this.mainContainer) return
      
      // 获取zoom-wrapper的实际内容尺寸
      const contentWidth = this.mainContainer.scrollWidth
      const contentHeight = this.mainContainer.scrollHeight
      
      // 概览图容器的最大尺寸
      const maxWidth = 200
      const maxHeight = 150
      
      // 计算缩放比例，确保内容能完全显示
      const scaleX = maxWidth / contentWidth
      const scaleY = maxHeight / contentHeight
      
      // 使用较小的缩放比例，确保内容完全显示
      this.scale = Math.min(scaleX, scaleY, 0.15) // 稍微提高最大缩放比例
      
    },
    
    // 重新创建缩略图内容
    regenerateThumbnail() {
      this.createThumbnailContent()
      this.updateViewportIndicator()
    },
    
    // 更新视口指示器位置
    updateViewportIndicator() {
      if (!this.mainContainer || !this.$refs.overviewContainer) {
        return
      }
      
      // 获取滚动容器（zoom-container）
      const scrollContainer = this.mainContainer.parentElement
      if (!scrollContainer) return
      
      // 获取主容器和概览容器的位置信息
      this.containerRect = this.mainContainer.getBoundingClientRect()
      this.overviewRect = this.$refs.overviewContainer.getBoundingClientRect()
      
      // 获取当前滚动位置（从滚动容器获取）
      this.scrollPosition = {
        x: scrollContainer.scrollLeft,
        y: scrollContainer.scrollTop
      }
      
    },
    
    // 处理滚动事件
    handleScroll() {
      // 使用requestAnimationFrame优化性能
      if (this.scrollAnimationFrame) {
        cancelAnimationFrame(this.scrollAnimationFrame)
      }
      
      this.scrollAnimationFrame = requestAnimationFrame(() => {
        this.updateViewportIndicator()
      })
    },
    
    // 处理窗口大小变化
    handleResize() {
      // 防抖处理
      if (this.resizeTimeout) {
        clearTimeout(this.resizeTimeout)
      }
      
      this.resizeTimeout = setTimeout(() => {
        this.updateContainerSize()
        this.updateViewportIndicator()
      }, 250)
    },
    
    // 处理内容变化
    handleContentChanged() {
      // 延迟重新创建缩略图，避免频繁更新
      if (this.contentChangeTimeout) {
        clearTimeout(this.contentChangeTimeout)
      }
      
      this.contentChangeTimeout = setTimeout(() => {
        this.regenerateThumbnail()
      }, 500) // 减少延迟时间，因为不需要生成快照
    },
    
    // 切换显示状态
    toggleVisibility() {
      this.isVisible = !this.isVisible
      this.$emit('visibility-changed', this.isVisible)
    },
    
    
    // 开始拖动视口指示器
    startDragViewport(event) {
      if (!this.mainContainer) return
      
      // 获取滚动容器
      const scrollContainer = this.mainContainer.parentElement
      if (!scrollContainer) return
      
      this.isDraggingViewport = true
      
      // 记录拖动开始位置
      this.dragStartPosition = {
        x: event.clientX,
        y: event.clientY
      }
      
      // 记录拖动开始时的滚动位置
      this.dragStartScrollPosition = {
        x: scrollContainer.scrollLeft,
        y: scrollContainer.scrollTop
      }
      
      // 阻止默认行为
      event.preventDefault()
      event.stopPropagation()
      
      // 添加全局事件监听器
      document.addEventListener('mousemove', this.handleDragViewportMove)
      document.addEventListener('mouseup', this.handleDragViewportEnd)
      
    },
    
    // 处理视口指示器拖动
    handleDragViewportMove(event) {
      if (!this.isDraggingViewport || !this.mainContainer) return
      
      // 获取滚动容器
      const scrollContainer = this.mainContainer.parentElement
      if (!scrollContainer) return
      
      // 计算拖动距离
      const deltaX = event.clientX - this.dragStartPosition.x
      const deltaY = event.clientY - this.dragStartPosition.y
      
      // 计算缩放比例
      const contentWidth = this.mainContainer.scrollWidth
      const contentHeight = this.mainContainer.scrollHeight
      const scaleX = 1 / this.scale
      const scaleY = 1 / this.scale
      
      // 计算新的滚动位置
      const newScrollX = this.dragStartScrollPosition.x + deltaX * scaleX
      const newScrollY = this.dragStartScrollPosition.y + deltaY * scaleY
      
      // 确保滚动位置在有效范围内
      // 考虑页面缩放对滚动范围的影响
      const maxScrollX = Math.max(0, contentWidth - scrollContainer.clientWidth)
      const maxScrollY = Math.max(0, contentHeight - scrollContainer.clientHeight)
      
      const finalScrollX = Math.max(0, Math.min(newScrollX, maxScrollX))
      const finalScrollY = Math.max(0, Math.min(newScrollY, maxScrollY))
      
      // 更新滚动位置
      scrollContainer.scrollLeft = finalScrollX
      scrollContainer.scrollTop = finalScrollY
    },
    
    // 结束拖动视口指示器
    handleDragViewportEnd() {
      if (!this.isDraggingViewport) return
      
      this.isDraggingViewport = false
      
      // 移除全局事件监听器
      document.removeEventListener('mousemove', this.handleDragViewportMove)
      document.removeEventListener('mouseup', this.handleDragViewportEnd)
      
    },
    
    // 点击概览图跳转到对应位置
    handleOverviewClick(event) {
      if (!this.mainContainer || !this.overviewRect) return
      
      // 如果正在拖动视口指示器，不执行点击跳转
      if (this.isDraggingViewport) return
      
      // 获取滚动容器（zoom-container）
      const scrollContainer = this.mainContainer.parentElement
      if (!scrollContainer) return
      
      const rect = this.$refs.overviewContainer.getBoundingClientRect()
      const clickX = event.clientX - rect.left
      const clickY = event.clientY - rect.top
      
      // 获取主容器的实际内容尺寸和视口尺寸
      const contentWidth = this.mainContainer.scrollWidth
      const contentHeight = this.mainContainer.scrollHeight
      const viewportWidth = scrollContainer.clientWidth
      const viewportHeight = scrollContainer.clientHeight
      
      // 计算在主容器中的对应位置
      // 使用实际的缩放比例来计算
      const scaleX = 1 / this.scale
      const scaleY = 1 / this.scale
      
      // 计算目标滚动位置（点击位置对应到内容中的位置）
      // 考虑页面缩放对点击位置的影响
      const targetX = clickX * scaleX - viewportWidth / 2
      const targetY = clickY * scaleY - viewportHeight / 2
      
      // 确保滚动位置在有效范围内
      const maxScrollX = Math.max(0, contentWidth - viewportWidth)
      const maxScrollY = Math.max(0, contentHeight - viewportHeight)
      
      const finalX = Math.max(0, Math.min(targetX, maxScrollX))
      const finalY = Math.max(0, Math.min(targetY, maxScrollY))
      
      
      // 滚动到目标位置（使用滚动容器，立即跳转）
      scrollContainer.scrollLeft = finalX
      scrollContainer.scrollTop = finalY
    }
  },
  
  watch: {
    visible(newVal) {
      this.isVisible = newVal
    },
    
    mainContainer: {
      handler(newContainer) {
        if (newContainer && !this.isInitialized) {
          this.isInitialized = true
          this.initializeOverview()
          this.setupEventListeners()
        }
      },
      immediate: true
    },
    
    // 监听缩放比例变化
    zoomLevel: {
      handler(newZoomLevel, oldZoomLevel) {
        if (newZoomLevel !== oldZoomLevel && this.isInitialized) {
          // 延迟更新，等待DOM更新完成
          this.$nextTick(() => {
            this.updateViewportIndicator()
          })
        }
      }
    }
  }
}
</script>

<style scoped>
.overview-map {
  position: fixed;
  bottom: 20px;
  left: 20px;
  z-index: 1000;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  border: 1px solid rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
  backdrop-filter: blur(10px);
}

.overview-map.visible {
  transform: translateY(0);
}

.overview-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 12px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  background: rgba(255, 255, 255, 0.8);
  border-radius: 8px 8px 0 0;
}

.overview-title {
  font-size: 12px;
  font-weight: bold;
  color: #333;
  padding-right: 10px;
}

.overview-controls {
  display: flex;
  gap: 4px;
}

.control-btn {
  width: 20px;
  height: 20px;
  border: none;
  background: rgba(0, 0, 0, 0.1);
  border-radius: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: bold;
  color: #333;
  transition: all 0.2s ease;
}

.control-btn:hover {
  background: rgba(0, 0, 0, 0.2);
  transform: scale(1.1);
}


.overview-content {
  padding: 8px;
}

.overview-container {
  position: relative;
  border: 1px solid rgba(0, 0, 0, 0.2);
  border-radius: 4px;
  overflow: hidden;
  cursor: pointer;
  background: #f8f9fa;
  min-height: 150px;
  min-width: 200px;
}

.thumbnail-container {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.thumbnail-content {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  user-select: none;
  opacity: 0.8;
}

.viewport-indicator {
  position: absolute;
  border: 2px solid #007bff;
  background: rgba(0, 123, 255, 0.1);
  pointer-events: auto;
  transition: all 0.1s ease;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.8);
  cursor: grab;
}

.viewport-indicator:hover {
  background: rgba(0, 123, 255, 0.2);
  border-color: #0056b3;
}

.viewport-indicator.dragging {
  cursor: grabbing;
  background: rgba(0, 123, 255, 0.3);
  border-color: #004085;
  box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.5);
  transition: none;
}




/* 响应式设计 */
@media (max-width: 768px) {
  .overview-map {
    bottom: 10px;
    left: 10px;
  }
  
  .overview-container {
    width: 150px;
    height: 112px;
  }
}
</style>
